package com.mini.service;

import cn.hutool.crypto.symmetric.AES;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.mini.config.EncryptField;
import com.mini.util.AsyncTaskManager;
import com.mini.util.HttpClientUtil;
import com.mini.vo.DeptVO;
import com.mini.vo.UserVO;
import com.sunlands.gateway.ApiGatewayClient;
import com.sunlands.gateway.ClientHttpResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.hibernate.Session;
import org.hibernate.jpa.HibernateEntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.JedisCommands;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Transient;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zhangxiaobin
 * @title: BaseService
 * @description: TODO
 * @date 2019/10/2711:35
 */
@Slf4j
public class BaseService {

    @Value("${mini.eureka.call.sign}")
    String reqSign;

    @Autowired
    AsyncTaskManager asyncTaskManager;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    protected AES bfAes;

    @Value("${mail.notification.env}")
    private String notificationEnv;

    @Value("${mail.notification.url}")
    private String notificationUrl;

    @Value("${mail.notification.users}")
    private String notificationUsers;

    @Autowired
    protected MiniAdminService miniAdminService;

    protected static final String conact_time = " 16:00:00";

    @Autowired
    private AES aes;

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    private ApiGatewayClient apiGatewayClient;

    @Value("${data.xingtusite.query.url}")
    private String xingtusiteurl;

    public String getShortUrl(String qrUrl) throws IOException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("longUrl", qrUrl);
        ClientHttpResponse response = null;
        for (int i = 0; i < 3; i++) {
            response = apiGatewayClient.postTextBody("/shortUrlApi/create", jsonObject.toJSONString());
            if(HttpStatus.SC_OK != response.getStatusCode() ){
                log.error("短链接 params=【{}】,resCode={} , resMsg={}" , jsonObject.toJSONString(),response.getStatusCode(),response);
                if(i == 2){
                    sendEmail("短链接信息接口状态码不正确;请求参数=【"+ jsonObject.toJSONString()  +"】请求返回code=【"+response.getStatusCode()+"】,请求返回内容=【"+response+"】");
                }
                continue;
            }
            break;
        }
        JSONObject responseBodyJSON = JSONObject.parseObject(response.getBodyStr());
        log.info("短链接responseBodyJSON={}",responseBodyJSON);
        return responseBodyJSON.getString("shortUrl");
    }

    //构建PageRequest
    protected PageRequest buildPageRequest(int pageNumber, int pagzSize, Sort sort) {
        return new PageRequest(pageNumber - 1, pagzSize, sort);
    }

    public void sendEmail(String message){
        if("test".equalsIgnoreCase(notificationEnv)){
            return;
        }
        try{
            asyncTaskManager.getExecutor().submit(new Runnable() {
                @Override
                public void run() {
                    Map<String, Object> requestEntity = new HashMap<>();
                    String ipAddress = "127.0.0.1";
                    try {
                        ipAddress = InetAddress.getLocalHost().getHostAddress();
                    }catch ( Exception ex){
                        log.error("sendMailNotification get ip error , ex={}", ex);
                    }
                    requestEntity.put("env", "mini-business-"+notificationEnv);
                    requestEntity.put("sys", "mini-business");
                    requestEntity.put("title", "报警服务IP【"+ipAddress+"】");
                    requestEntity.put("emailAddr", notificationUsers);
                    requestEntity.put("ip", ipAddress);
                    requestEntity.put("msg", message);
                    boolean successState = true;
                    int httpCount = 0 ;
                    do {
                        try {
                            HttpClientUtil.post(notificationUrl,requestEntity);
                            successState = true;
                        } catch (IOException e) {
                            log.error("send email error, msg = {}, {}",message,e);
                            successState = false;
                            httpCount++;
                        }
                    }while (!successState && httpCount < 5);
                }
            });
        }catch (Exception ex){
            log.error("send email error message = {} ,ex= {}",message, ex);
        }
    }

    protected boolean tryLock(String key){
        try {
            String result = (String) redisTemplate.execute((RedisCallback<String>) connection -> {
                JedisCommands commands = (JedisCommands) connection.getNativeConnection();
                return commands.set(key, key, "NX", "EX", 5);
            });
            return !StringUtils.isEmpty(result);
        } catch (Exception e) {
            log.error("getNewUsePushLock error", e);
        }
        return false;
    }

    protected void releaseLockKey(String key){
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("releaseNewUsePushLock error", e);
        }
    }

    protected List<Long> scopedAdvertisingUserIds(Long userId){
       try{
           List<Long> data = miniAdminService.scopedAdvertisingUserIds(userId);
           return data;
       }catch (Exception ex){
           log.error("调用mini-admin【api/users/scopedUserIds】异常；params=【{}】,ex = {}",userId,ex);
           sendEmail("调用mini-admin【api/users/scopedUserIds】异常，params=【"+userId+"】,ex =【"+ ex.getMessage() +"】");
       }
        return null;
    }

    protected List<UserVO> scopedOperationUserList(String token){
        try{
            List<UserVO> data = miniAdminService.scopedOperationUserList(token);
            return data;
        }catch (Exception ex){
            log.error("调用mini-admin【api/users/scopedOperationUserList】异常；params=【{}】,ex = {}",token,ex);
            sendEmail("调用mini-admin【api/users/scopedOperationUserList】异常，params=【"+token+"】,ex =【"+ ex.getMessage() +"】");
        }
        return null;
    }

    protected List<Long> scopedOperationUserIdsHistory(Long userId){
        try{
            List<Long> data = miniAdminService.scopedOperationUserIdsHistory(userId);
            return data;
        }catch (Exception ex){
            log.error("调用mini-admin【api/users/scopedUserIds】异常；params=【{}】,ex = {}",userId,ex);
            sendEmail("调用mini-admin【api/users/scopedUserIds】异常，params=【"+userId+"】,ex =【"+ ex.getMessage() +"】");
        }
        return null;
    }

    protected List<DeptVO> groupIdsInfo(List<String> depts,Long userId){
        try{
            if (CollectionUtils.isEmpty(depts)) {
                return new ArrayList<>();
            }
            Set<Long> deptIds = Sets.newHashSet();
            depts.forEach(o->deptIds.add(Long.valueOf(o)));
            List<DeptVO> data = miniAdminService.findGroupInfos(deptIds,userId);
            if(data == null || data.size() <=0 ){
                log.debug("调用mini-admin【api/dept/linear/operation/filter】数据为空；params=【{}】",depts.toString());
                sendEmail("调用mini-admin【api/dept/linear/operation/filter】数据为空，params=【"+depts.toString()+"】");
                return null;
            }
            return data;
        }catch (Exception ex){
            log.error("调用mini-admin【api/dept/linear/operation/filter】异常；params=【{}】,ex = {}",depts.toString(),ex);
            sendEmail("调用mini-admin【api/dept/linear/operation/filter】异常，params=【"+depts.toString()+"】,ex =【"+ ex.getMessage() +"】");
        }
        return null;
    }

    public String encryptField(String val) {
        if (StringUtils.isBlank(val)) {
            return null;
        }
        boolean need = false;
        try {
            aes.decrypt(val);
        } catch (RuntimeException r) {
            need = true;
        }
        if (!need) {
            return val;
        }
        return aes.encryptHex(val);
    }

    public String decryptField(String val) {
        if (StringUtils.isBlank(val)) {
            return null;
        }
        try {
            return aes.decryptStr(val);
        } catch (RuntimeException r) {
        }
        return val;
    }

    public Object encryptObj(Object obj) {
        if(obj==null){
            return null;
        }
        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if(Objects.nonNull(field.getAnnotation(Transient.class))){
                    evictObj(field.get(obj));
                }
                if (Objects.isNull(field.getAnnotation(EncryptField.class))) {
                    field.setAccessible(false);
                    continue;
                }
                String val = encryptField((String) field.get(obj));
                field.set(obj, val);
                field.setAccessible(false);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public void evictObj(Object obj){
        try {
            Session session = ((HibernateEntityManager) entityManager).getSession();
            session.evict(obj);
        }catch (Exception e){
        }
    }

    public Object decryptObj(Object obj) {
        if(obj==null){
            return null;
        }
        try {
            evictObj(obj);
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (Objects.isNull(field.getAnnotation(EncryptField.class))) {
                    field.setAccessible(false);
                    continue;
                }
                String val = decryptField((String) field.get(obj));
                field.set(obj, val);
                field.setAccessible(false);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public List decryptObjs(List objectList) {
        if(CollectionUtils.isEmpty(objectList)){
            return objectList;
        }
        List result = new ArrayList();
        objectList.forEach(o->{
            o = decryptObj(o);
            if(Objects.nonNull(o)){
                result.add(o);
            }

        });
        return result;
    }

    /**
     * 查询星图站点的AB模式
     * @param siteId
     * @return
     */
    public Integer checkXingTuSite(String siteId){
        String url = xingtusiteurl+siteId;
        try {
            String result = HttpClientUtil.get(url, null);
            log.info("siteId={} result={}",siteId,result);
            if (StringUtils.isNotBlank(result)) {
                JSONObject data = JSONObject.parseObject(result);
                String bizCardTypeCode = data.getString("bizCardTypeCode");
                if(StringUtils.isNotBlank(bizCardTypeCode)){
                    if("NOTMOBILE".equals(bizCardTypeCode)){
                        return 2;
                    }else if("ISMOBILE".equals(bizCardTypeCode)){
                        return 1;
                    }else {
                        return null;
                    }
                }else {
                    return null;
                }
            }
        }catch (Exception e){
            log.error("查询星图站点信息异常",e);
        }
        return null;
    }

    protected String convertSkuName(String innerSkuName){
        String outSkuName = innerSkuName;
        if(StringUtils.isBlank(innerSkuName)){
            return innerSkuName;
        }

        if("会计".equals(innerSkuName)){
            outSkuName = "会计职称";
        }else if("学历".equals(innerSkuName)){
            outSkuName = "自考";
        }else if("心理".equals(innerSkuName)){
            outSkuName = "心理咨询师资格证";
        }else if("研究生".equals(innerSkuName)){
            outSkuName = "硕士研究生";
        }
        return outSkuName;
    }

    public String bfEncrypt(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return bfAes.encryptHex(str);
    }

    static class RegexUtil {

        public static final String REGEX_MOBILE = "(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}";

        public static final String REGEX_QQ = "[1-9]\\d{4,10}";

        public static final String REGEX_WECHAT = "[a-zA-Z]{1}[-_a-zA-Z0-9]{5,19}";

        public static String regexMobile(String content){
            Pattern p = Pattern.compile(REGEX_MOBILE);
            Matcher m = p.matcher(content);
            String paramStr = new String(content);
            while (m.find()) { //一定需要先查找再调用group获取电话号码
                paramStr = paramStr.replaceAll(m.group(), m.group().substring(0, 3) + "****"+m.group().substring(7));
            }
            return paramStr;
        }

        public static String regexQQ(String content){
            Pattern p = Pattern.compile(REGEX_QQ);
            Matcher m = p.matcher(content);
            String paramStr = new String(content);
            while (m.find()) {
                paramStr = paramStr.replaceAll(m.group(), m.group().substring(0, 3) + "***"+m.group().substring(5));
            }
            return paramStr;
        }

        public static String regexWechat(String content){
            Pattern p = Pattern.compile(REGEX_WECHAT);
            Matcher m = p.matcher(content);
            String paramStr = new String(content);
            while (m.find()) {
                paramStr = paramStr.replaceAll(m.group(), m.group().substring(0, 3) + "***"+m.group().substring(6));
            }
            return paramStr;
        }
    }
}
